package org.zxp.thread.volatileTest.singleton;

/**
 * @program: zxp-thread-test
 * @description:  懒汉模式的问题写法
 * 1、多线程下无法保证单例
 * @author: X-Pacific zhang
 * @create: 2019-05-10 17:37
 **/
public class LazySingletonill {
    private static LazySingletonill lazySingletonill = null;

    private LazySingletonill(){
    }

    /**
     * 多线程下无法保证单例
     * @return
     */
    public static LazySingletonill getInstance1(){
        if(lazySingletonill == null){
            try {
                //如果加上休眠则更严重（不能保证单例），为什么呢，休眠后在启动有CPU调度，不连续导致问题出现
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lazySingletonill = new LazySingletonill();
        }
        return lazySingletonill;
    }

    /**
     * 能保证单例，如果里面内容复杂且耗时就性能不好
     * @return
     */
    public static synchronized LazySingletonill getInstance2(){
        if(lazySingletonill == null){
            try {
                //如果加上休眠则更严重（不能保证单例），为什么呢，休眠后在启动有CPU调度，不连续导致问题出现
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lazySingletonill = new LazySingletonill();
        }
        return lazySingletonill;
    }

    /**
     * 不能保证单例
     * 原因：A 、B两线程同时进==null的判断，A线程获得锁B线程阻塞，A线程实例化后return B线程也去实例化return
     * @return
     */
    public static LazySingletonill getInstance3(){
        if(lazySingletonill == null){
            try {
                //如果加上休眠则更严重（不能保证单例），为什么呢，休眠后在启动有CPU调度，不连续导致问题出现
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (LazySingletonill.class){
                lazySingletonill = new LazySingletonill();
            }
        }
        return lazySingletonill;
    }

    /**
     * 不能保证调用后获得正确结果
     * double check写法
     * 原因：指令重排后可能返回不正常结果
     * @return
     */
    public static LazySingletonill getInstance4(){
        if(lazySingletonill == null){
            try {
                //如果加上休眠则更严重（不能保证单例），为什么呢，休眠后在启动有CPU调度，不连续导致问题出现
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (LazySingletonill.class){
                if (lazySingletonill == null) {
                    lazySingletonill = new LazySingletonill();
                }
            }
        }
        return lazySingletonill;
    }

    public static void main(String[] args){
        //非多线程没问题
        for (int i = 0; i < 100; i++) {
            System.out.println(LazySingletonill.getInstance1().hashCode());
        }

        //多线程下无法保证单例
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(LazySingletonill.getInstance1().hashCode());
            }).start();
        }

        //能保证单例，但性能不好
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(LazySingletonill.getInstance2().hashCode());
            }).start();
        }

        //不能保证单例
        // 原因：A 、B两线程同时进==null的判断，A线程获得锁B线程阻塞，A线程实例化后return B线程也去实例化return
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(LazySingletonill.getInstance3());
            }).start();
        }
        //double check写法
        //原因：指令重排后可能返回不正常结果
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(LazySingletonill.getInstance4().hashCode());
            }).start();
        }
    }



}
